home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Sample Code / MoreFiles 1.3.1 / FSpCompat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-16  |  22.6 KB  |  791 lines  |  [TEXT/MMCC]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    FSSpec compatibility functions.
  5. **
  6. **    by Jim Luther, Apple Developer Technical Support
  7. **
  8. **    File:        FSpCompat.c
  9. **
  10. **    Copyright © 1992-1995 Apple Computer, Inc.
  11. **    All rights reserved.
  12. **
  13. **    You may incorporate this sample code into your applications without
  14. **    restriction, though the sample code has been provided "AS IS" and the
  15. **    responsibility for its operation is 100% yours.  However, what you are
  16. **    not permitted to do is to redistribute the source as "DSC Sample Code"
  17. **    after having made changes. If you're going to re-distribute the source,
  18. **    we require that you make it clear in the source that the code was
  19. **    descended from Apple Sample Code, but that you've made changes.
  20. */
  21.  
  22. #define    GENERATENODATA 0
  23.  
  24. #include <Types.h>
  25. #include <Errors.h>
  26. #include <LowMem.h>
  27. #include <Gestalt.h>
  28. #include <Resources.h>
  29. #include <Script.h>
  30. #include "MoreFilesExtras.h"
  31. #include "FSpCompat.h"
  32.  
  33. /*****************************************************************************/
  34.  
  35. /* local constants */
  36.  
  37. enum {
  38.     gestaltBugFixAttrsTwo                    = 'bugy',
  39.     gestaltFSpExchangeFilesCompatibilityFix    = 26,
  40.     gestaltBugFixAttrsThree                    = 'bugx',
  41.     gestaltFSpCreateScriptSupportFix        = 1
  42. };
  43.  
  44. /*****************************************************************************/
  45.  
  46. /* static prototypes */
  47.  
  48. static    Boolean    FSHasFSSpecCalls(void);
  49.  
  50. static    Boolean    QTHasFSSpecCalls(void);
  51.  
  52. static    Boolean    HasFSpExchangeFilesCompatibilityFix(void);
  53.  
  54. static    Boolean    HasFSpCreateScriptSupportFix(void);
  55.  
  56. static    OSErr    GenerateUniqueName(short volume,
  57.                                    long *startSeed,
  58.                                    long dir1,
  59.                                    long dir2,
  60.                                    StringPtr uniqueName);
  61.  
  62. /*****************************************************************************/
  63.  
  64. /* FSHasFSSpecCalls returns true if the file system provides FSSpec calls. */
  65.  
  66. static    Boolean    FSHasFSSpecCalls(void)
  67. {
  68.     long            response;
  69. #if !GENERATENODATA
  70.     static Boolean    tested = false;
  71.     static Boolean    result = false;
  72. #else
  73.     Boolean    result = false;
  74. #endif
  75.     
  76. #if !GENERATENODATA
  77.     if ( !tested )
  78.     {
  79.         tested = true;
  80. #endif
  81.         if ( Gestalt(gestaltFSAttr, &response) == noErr )
  82.         {
  83.             result = ((response & (1L << gestaltHasFSSpecCalls)) != 0);
  84.         }
  85. #if !GENERATENODATA
  86.     }
  87. #endif
  88.     return ( result );
  89. }
  90.  
  91. /*****************************************************************************/
  92.  
  93. /* QTHasFSSpecCalls returns true if QuickTime provides FSSpec calls */
  94. /* except for FSpExchangeFiles. */
  95.  
  96. static    Boolean    QTHasFSSpecCalls(void)
  97. {
  98.     long            response;
  99. #if !GENERATENODATA
  100.     static Boolean    tested = false;
  101.     static Boolean    result = false;
  102. #else
  103.     Boolean    result = false;
  104. #endif
  105.     
  106. #if !GENERATENODATA
  107.     if ( !tested )
  108.     {
  109.         tested = true;
  110. #endif
  111.         result = (Gestalt(gestaltQuickTimeVersion, &response) == noErr);
  112. #if !GENERATENODATA
  113.     }
  114. #endif
  115.     return ( result );
  116. }
  117.  
  118. /*****************************************************************************/
  119.  
  120. /* HasFSpExchangeFilesCompatibilityFix returns true if FSpExchangeFiles */
  121. /* compatibility code has been fixed in system software. */
  122.  
  123. static    Boolean    HasFSpExchangeFilesCompatibilityFix(void)
  124. {
  125.     long            response;
  126. #if !GENERATENODATA
  127.     static Boolean    tested = false;
  128.     static Boolean    result = false;
  129. #else
  130.     Boolean    result = false;
  131. #endif
  132.     
  133. #if !GENERATENODATA
  134.     if ( !tested )
  135.     {
  136.         tested = true;
  137. #endif
  138.         if ( Gestalt(gestaltBugFixAttrsTwo, &response) == noErr )
  139.         {
  140.             result = ((response & (1L << gestaltFSpExchangeFilesCompatibilityFix)) != 0);
  141.         }
  142. #if !GENERATENODATA
  143.     }
  144. #endif
  145.     return ( result );
  146. }
  147.  
  148. /*****************************************************************************/
  149.  
  150. /* HasFSpCreateScriptSupportFix returns true if FSpCreate and */
  151. /* FSpCreateResFile have been fixed in system software to correctly set */
  152. /* the scriptCode in the volume's catalog. */
  153.  
  154. static    Boolean    HasFSpCreateScriptSupportFix(void)
  155. {
  156.     long            response;
  157. #if !GENERATENODATA
  158.     static Boolean    tested = false;
  159.     static Boolean    result = false;
  160. #else
  161.     Boolean    result = false;
  162. #endif
  163.     
  164. #if !GENERATENODATA
  165.     if ( !tested )
  166.     {
  167.         tested = true;
  168. #endif
  169.         if ( Gestalt(gestaltBugFixAttrsThree, &response) == noErr )
  170.         {
  171.             result = ((response & (1L << gestaltFSpCreateScriptSupportFix)) != 0);
  172.         }
  173. #if !GENERATENODATA
  174.     }
  175. #endif
  176.     return ( result );
  177. }
  178.  
  179. /*****************************************************************************/
  180.  
  181. /*
  182. **    File Manager FSp calls
  183. */
  184.  
  185. /*****************************************************************************/
  186.  
  187. pascal    OSErr    FSMakeFSSpecCompat(short vRefNum,
  188.                                    long dirID,
  189.                                    ConstStr255Param fileName,
  190.                                    FSSpecPtr spec)
  191. {
  192.     OSErr    result;
  193.     Boolean    isDirectory;
  194.     
  195.     /* Let the file system create the FSSpec if it can since it does the job */
  196.     /* much more efficiently than I can. */
  197.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  198.     {
  199.         result = FSMakeFSSpec(vRefNum, dirID, fileName, spec);
  200.         /* Fix a bug in Macintosh PC Exchange's MakeFSSpec code where 0 is */
  201.         /* returned in the parID field when making an FSSpec to the volume's */
  202.         /* root directory by passing a full pathname in MakeFSSpec's */
  203.         /* fileName parameter. */
  204.         if ( (result == noErr) && (spec->parID == 0) )
  205.             spec->parID = fsRtParID;
  206.     }
  207.     else
  208.         result = GetObjectLocation(vRefNum, dirID, (StringPtr)fileName,
  209.                                     &(spec->vRefNum), &(spec->parID), spec->name,
  210.                                     &isDirectory);
  211.     return ( result );
  212. }
  213.  
  214. /*****************************************************************************/
  215.  
  216. pascal    OSErr    FSpOpenDFCompat(const FSSpec *spec,
  217.                                 char permission,
  218.                                 short *refNum)
  219. {
  220.     OSErr            result;
  221.     HParamBlockRec    pb;
  222.  
  223.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  224.         return ( FSpOpenDF(spec, permission, refNum) );
  225.     else
  226.     {
  227.         pb.ioParam.ioVRefNum = spec->vRefNum;
  228.         pb.fileParam.ioDirID = spec->parID;
  229.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  230.         pb.ioParam.ioVersNum = 0;
  231.         pb.ioParam.ioPermssn = permission;
  232.         pb.ioParam.ioMisc = NULL;
  233.         result = PBHOpenSync(&pb);    /* OpenDF not supported by System 6, so use Open */
  234.         *refNum = pb.ioParam.ioRefNum;
  235.         return ( result );
  236.     }
  237. }
  238.  
  239. /*****************************************************************************/
  240.  
  241. pascal    OSErr    FSpOpenRFCompat(const FSSpec *spec,
  242.                                 char permission,
  243.                                 short *refNum)
  244. {
  245.     OSErr            result;
  246.     HParamBlockRec    pb;
  247.  
  248.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  249.         return ( FSpOpenRF(spec, permission, refNum) );
  250.     else
  251.     {
  252.         pb.ioParam.ioVRefNum = spec->vRefNum;
  253.         pb.fileParam.ioDirID = spec->parID;
  254.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  255.         pb.ioParam.ioVersNum = 0;
  256.         pb.ioParam.ioPermssn = permission;
  257.         pb.ioParam.ioMisc = NULL;
  258.         result = PBHOpenRFSync(&pb);
  259.         *refNum = pb.ioParam.ioRefNum;
  260.         return ( result );
  261.     }
  262. }
  263.  
  264. /*****************************************************************************/
  265.  
  266. pascal    OSErr    FSpCreateCompat(const FSSpec *spec,
  267.                                 OSType creator,
  268.                                 OSType fileType,
  269.                                 ScriptCode scriptTag)
  270. {
  271.     OSErr            result;
  272.     UniversalFMPB    pb;
  273.     
  274.     if ( (FSHasFSSpecCalls() || QTHasFSSpecCalls()) && HasFSpCreateScriptSupportFix() )
  275.         return ( FSpCreate(spec, creator, fileType, scriptTag) );
  276.     else
  277.     {
  278.         pb.hPB.fileParam.ioVRefNum = spec->vRefNum;
  279.         pb.hPB.fileParam.ioDirID = spec->parID;
  280.         pb.hPB.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  281.         pb.hPB.fileParam.ioFVersNum = 0;
  282.         result = PBHCreateSync(&(pb.hPB));
  283.         if ( result == noErr )
  284.         {
  285.             /* get info on created item */
  286.             pb.ciPB.hFileInfo.ioFDirIndex = 0;
  287.             result = PBGetCatInfoSync(&(pb.ciPB));
  288.             if ( result == noErr )
  289.             {
  290.                 /* Set fdScript in FXInfo */
  291.                 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  292.                 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  293.                 /* (smRoman is 0). fdScript is valid if high bit is set (see IM-6, page 9-38) */
  294.                 pb.ciPB.hFileInfo.ioFlXFndrInfo.fdScript = (scriptTag >= smRoman) ?
  295.                                                             ((char)scriptTag | (char)0x80) :
  296.                                                             (smRoman);
  297.                 /* Set creator/fileType */
  298.                 pb.ciPB.hFileInfo.ioFlFndrInfo.fdCreator = creator;
  299.                 pb.ciPB.hFileInfo.ioFlFndrInfo.fdType = fileType;
  300.                 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  301.                 pb.ciPB.hFileInfo.ioDirID = spec->parID;
  302.                 result = PBSetCatInfoSync(&(pb.ciPB));
  303.             }
  304.         }
  305.         return ( result );
  306.     }
  307. }
  308.  
  309. /*****************************************************************************/
  310.  
  311. pascal    OSErr    FSpDirCreateCompat(const FSSpec *spec,
  312.                                    ScriptCode scriptTag,
  313.                                    long *createdDirID)
  314. {
  315.     OSErr            result;
  316.     UniversalFMPB    pb;
  317.  
  318.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  319.         return ( FSpDirCreate(spec, scriptTag, createdDirID) );
  320.     else
  321.     {
  322.         pb.hPB.fileParam.ioVRefNum = spec->vRefNum;
  323.         pb.hPB.fileParam.ioDirID = spec->parID;
  324.         pb.hPB.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  325.         result = PBDirCreateSync(&(pb.hPB));
  326.         *createdDirID = pb.hPB.fileParam.ioDirID;
  327.         if ( result == noErr )
  328.         {
  329.             /* get info on created item */
  330.             pb.ciPB.dirInfo.ioFDirIndex = 0;
  331.             pb.ciPB.dirInfo.ioDrDirID = spec->parID;
  332.             result = PBGetCatInfoSync(&(pb.ciPB));
  333.             if ( result == noErr )
  334.             {
  335.                 /* Set frScript in DXInfo */
  336.                 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  337.                 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  338.                 /* (smRoman is 0). frScript is valid if high bit is set (see IM-6, page 9-38) */
  339.                 pb.ciPB.dirInfo.ioDrFndrInfo.frScript = (scriptTag >= smRoman) ?
  340.                                                             ((char)scriptTag | (char)0x80) :
  341.                                                             (smRoman);
  342.                 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  343.                 pb.ciPB.dirInfo.ioDrDirID = spec->parID;            
  344.                 result = PBSetCatInfoSync(&(pb.ciPB));
  345.             }
  346.         }
  347.         return ( result );
  348.     }
  349. }
  350.  
  351. /*****************************************************************************/
  352.  
  353. pascal    OSErr    FSpDeleteCompat(const FSSpec *spec)
  354. {
  355.     HParamBlockRec    pb;
  356.  
  357.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  358.         return ( FSpDelete(spec) );
  359.     else
  360.     {
  361.         pb.ioParam.ioVRefNum = spec->vRefNum;
  362.         pb.fileParam.ioDirID = spec->parID;
  363.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  364.         pb.ioParam.ioVersNum = 0;
  365.         return ( PBHDeleteSync(&pb) );
  366.     }
  367. }
  368.  
  369. /*****************************************************************************/
  370.  
  371. pascal    OSErr    FSpGetFInfoCompat(const FSSpec *spec,
  372.                                   FInfo *fndrInfo)
  373. {
  374.     OSErr            result;
  375.     HParamBlockRec    pb;
  376.  
  377.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  378.         return ( FSpGetFInfo(spec, fndrInfo) );
  379.     else
  380.     {
  381.         pb.fileParam.ioVRefNum = spec->vRefNum;
  382.         pb.fileParam.ioDirID = spec->parID;
  383.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  384.         pb.fileParam.ioFVersNum = 0;
  385.         pb.fileParam.ioFDirIndex = 0;
  386.         result = PBHGetFInfoSync(&pb);
  387.         *fndrInfo = pb.fileParam.ioFlFndrInfo;
  388.         return ( result );
  389.     }
  390. }
  391.  
  392. /*****************************************************************************/
  393.  
  394. pascal    OSErr    FSpSetFInfoCompat(const FSSpec *spec,
  395.                                   const FInfo *fndrInfo)
  396. {
  397.     OSErr            result;
  398.     HParamBlockRec    pb;
  399.  
  400.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  401.         return ( FSpSetFInfo(spec, fndrInfo) );
  402.     else
  403.     {
  404.         pb.fileParam.ioVRefNum = spec->vRefNum;
  405.         pb.fileParam.ioDirID = spec->parID;
  406.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  407.         pb.fileParam.ioFVersNum = 0;
  408.         pb.fileParam.ioFDirIndex = 0;
  409.         result = PBHGetFInfoSync(&pb);
  410.         if ( result == noErr )
  411.         {
  412.             pb.fileParam.ioFlFndrInfo = *fndrInfo;
  413.             pb.fileParam.ioDirID = spec->parID;
  414.             result = PBHSetFInfoSync(&pb);
  415.         }
  416.         return ( result );
  417.     }
  418. }
  419.  
  420. /*****************************************************************************/
  421.  
  422. pascal    OSErr    FSpSetFLockCompat(const FSSpec *spec)
  423. {
  424.     HParamBlockRec    pb;
  425.  
  426.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  427.         return ( FSpSetFLock(spec) );
  428.     else
  429.     {
  430.         pb.fileParam.ioVRefNum = spec->vRefNum;
  431.         pb.fileParam.ioDirID = spec->parID;
  432.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  433.         pb.fileParam.ioFVersNum = 0;
  434.         return ( PBHSetFLockSync(&pb) );
  435.     }
  436. }
  437.  
  438. /*****************************************************************************/
  439.  
  440. pascal    OSErr    FSpRstFLockCompat(const FSSpec *spec)
  441. {
  442.     HParamBlockRec    pb;
  443.  
  444.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  445.         return ( FSpRstFLock(spec) );
  446.     else
  447.     {
  448.         pb.fileParam.ioVRefNum = spec->vRefNum;
  449.         pb.fileParam.ioDirID = spec->parID;
  450.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  451.         pb.fileParam.ioFVersNum = 0;
  452.         return ( PBHRstFLockSync(&pb) );
  453.     }
  454. }
  455.  
  456. /*****************************************************************************/
  457.  
  458. pascal    OSErr    FSpRenameCompat(const FSSpec *spec,
  459.                                 ConstStr255Param newName)
  460. {
  461.     HParamBlockRec    pb;
  462.  
  463.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  464.         return ( FSpRename(spec, newName) );
  465.     else
  466.     {
  467.         pb.ioParam.ioVRefNum = spec->vRefNum;
  468.         pb.fileParam.ioDirID = spec->parID;
  469.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  470.         pb.ioParam.ioVersNum = 0;
  471.         pb.ioParam.ioMisc = (Ptr) newName;
  472.         return ( PBHRenameSync(&pb) );
  473.     }
  474. }
  475.  
  476. /*****************************************************************************/
  477.  
  478. pascal    OSErr    FSpCatMoveCompat(const FSSpec *source,
  479.                                  const FSSpec *dest)
  480. {
  481.     CMovePBRec    pb;
  482.  
  483.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  484.         return ( FSpCatMove(source, dest) );
  485.     else
  486.     {
  487.         /* source and destination volume must be the same */
  488.         if ( source->vRefNum != dest->vRefNum )
  489.             return ( paramErr );
  490.         
  491.         pb.ioNamePtr = (StringPtr) &(source->name);
  492.         pb.ioVRefNum = source->vRefNum;
  493.         pb.ioDirID = source->parID;
  494.         pb.ioNewDirID = dest->parID;
  495.         pb.ioNewName = (StringPtr) &(dest->name);
  496.         return ( PBCatMoveSync(&pb) );
  497.     }
  498. }
  499.  
  500. /*****************************************************************************/
  501.  
  502. /* GenerateUniqueName generates a name that is unique in both dir1 and dir2 */
  503. /* on the specified volume. Ripped off from Feldman's code. */
  504.  
  505. static    OSErr    GenerateUniqueName(short volume,
  506.                                    long *startSeed,
  507.                                    long dir1,
  508.                                    long dir2,
  509.                                    StringPtr uniqueName)
  510. {
  511.     OSErr            error = noErr;
  512.     long            i;
  513.     CInfoPBRec        cinfo;
  514.     unsigned char    hexStr[16];
  515.     
  516.     for ( i = 0; i < 16; ++i )
  517.     {
  518.         if ( i < 10 )
  519.             hexStr[i] = 0x30 + i;
  520.         else
  521.             hexStr[i] = 0x37 + i;
  522.     }
  523.     
  524.     cinfo.hFileInfo.ioVRefNum = volume;
  525.     cinfo.hFileInfo.ioFDirIndex = 0;
  526.     cinfo.hFileInfo.ioNamePtr = uniqueName;
  527.  
  528.     while ( error != fnfErr )
  529.     {
  530.         (*startSeed)++;        
  531.         cinfo.hFileInfo.ioNamePtr[0] = 8;
  532.         for ( i = 1; i <= 8; i++ )
  533.         {
  534.             cinfo.hFileInfo.ioNamePtr[i] = hexStr[((*startSeed >> ((8-i)*4)) & 0xf)];
  535.         }
  536.         cinfo.hFileInfo.ioDirID = dir1;
  537.         error = fnfErr;
  538.         for ( i = 1; i <= 2; i++ )
  539.         {
  540.             error = error & PBGetCatInfoSync(&cinfo);
  541.             cinfo.hFileInfo.ioDirID = dir2;
  542.             if ( (error != fnfErr) && (error != noErr) )
  543.                 return ( error );
  544.         }
  545.     }
  546.     return ( noErr );
  547. }
  548.  
  549. /*****************************************************************************/
  550.  
  551. pascal    OSErr    FSpExchangeFilesCompat(const FSSpec *source,
  552.                                        const FSSpec *dest)
  553. {
  554.     HParamBlockRec            pb;
  555.     CInfoPBRec                catInfoSource, catInfoDest;
  556.     OSErr                    error, error2;
  557.     Str31                    unique1, unique2;
  558.     StringPtr                unique1Ptr, unique2Ptr, swapola;
  559.     GetVolParmsInfoBuffer    volInfo;
  560.     long                    theSeed, temp;
  561.     
  562.     if ( FSHasFSSpecCalls() && HasFSpExchangeFilesCompatibilityFix() )
  563.         return ( FSpExchangeFiles(source, dest) );
  564.     else
  565.     {
  566.         /* Make sure the source and destination are on the same volume */
  567.         if ( source->vRefNum != dest->vRefNum )
  568.             return ( paramErr );
  569.         
  570.         /* Try PBExchangeFiles first since it preserves the file ID reference */
  571.         pb.fidParam.ioNamePtr = (StringPtr) &(source->name);
  572.         pb.fidParam.ioVRefNum = source->vRefNum;
  573.         pb.fidParam.ioDestNamePtr = (StringPtr) &(dest->name);
  574.         pb.fidParam.ioDestDirID = dest->parID;
  575.         pb.fidParam.ioSrcDirID = source->parID;
  576.     
  577.         error = PBExchangeFilesSync(&pb);
  578.     
  579.         /* Note: The compatibility case won't work for files with *Btree control blocks. */
  580.         /* Right now the only *Btree files are created by the system. */
  581.         if ( error != noErr )
  582.         {
  583.             pb.ioParam.ioNamePtr = NULL;
  584.             pb.ioParam.ioBuffer = (Ptr) &volInfo;
  585.             pb.ioParam.ioReqCount = sizeof(volInfo);
  586.             error2 = PBHGetVolParmsSync(&pb);
  587.             
  588.             /* continue if volume has no fileID support (or no GetVolParms support) */
  589.             if ( (error2 == noErr) && hasFileIDs(volInfo) )
  590.                 return ( error );
  591.     
  592.             /* Get the catalog information for each file */
  593.             /* and make sure both files are *really* files */
  594.             catInfoSource.hFileInfo.ioVRefNum = source->vRefNum;
  595.             catInfoSource.hFileInfo.ioFDirIndex = 0;
  596.             catInfoSource.hFileInfo.ioNamePtr = (StringPtr) &(source->name);
  597.             catInfoSource.hFileInfo.ioDirID = source->parID;
  598.             catInfoSource.hFileInfo.filler2 = 0;
  599.             error = PBGetCatInfoSync(&catInfoSource);
  600.             if ( error != noErr )
  601.                 return ( error );
  602.             if ( (catInfoSource.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
  603.                 return ( notAFileErr );
  604.             
  605.             catInfoDest.hFileInfo.ioVRefNum = dest->vRefNum;
  606.             catInfoDest.hFileInfo.ioFDirIndex = 0;
  607.             catInfoDest.hFileInfo.ioNamePtr = (StringPtr) &(dest->name);
  608.             catInfoDest.hFileInfo.ioDirID = dest->parID;
  609.             catInfoDest.hFileInfo.filler2 = 0;
  610.             error = PBGetCatInfoSync(&catInfoDest);
  611.             if ( error != noErr )
  612.                 return ( error );
  613.             if ( (catInfoDest.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
  614.                 return ( notAFileErr );
  615.             
  616.             /* generate 2 filenames that are unique in both directories */
  617.             theSeed = 0x64666A6C;    /* a fine unlikely filename */
  618.             unique1Ptr = (StringPtr)&unique1;
  619.             unique2Ptr = (StringPtr)&unique2;
  620.             
  621.             error = GenerateUniqueName(source->vRefNum, &theSeed, source->parID, dest->parID, unique1Ptr);
  622.             if ( error != noErr )
  623.                 return ( error );
  624.     
  625.             GenerateUniqueName(source->vRefNum, &theSeed, source->parID, dest->parID, unique2Ptr);
  626.             if ( error != noErr )
  627.                 return ( error );
  628.     
  629.             /* rename source to unique1 */
  630.             pb.fileParam.ioNamePtr = (StringPtr) &(source->name);
  631.             pb.ioParam.ioMisc = (Ptr) unique1Ptr;
  632.             pb.ioParam.ioVersNum = 0;
  633.             error = PBHRenameSync(&pb);
  634.             if ( error != noErr )
  635.                 return ( error );        
  636.             
  637.             /* rename dest to unique2 */
  638.             pb.ioParam.ioMisc = (Ptr) unique2Ptr;
  639.             pb.ioParam.ioVersNum = 0;
  640.             pb.fileParam.ioNamePtr = (StringPtr) &(dest->name);
  641.             pb.fileParam.ioDirID = dest->parID;
  642.             error = PBHRenameSync(&pb);
  643.             if ( error != noErr )
  644.                 goto error2;    /* back out gracefully by renaming unique1 back to source */
  645.                 
  646.             /* If files are not in same directory, swap their locations */
  647.             if ( source->parID != dest->parID )
  648.             {
  649.                 /* move source file to dest directory */
  650.                 pb.copyParam.ioNamePtr = unique1Ptr;
  651.                 pb.copyParam.ioNewName = NULL;
  652.                 pb.copyParam.ioNewDirID = dest->parID;
  653.                 pb.copyParam.ioDirID = source->parID;
  654.                 error = PBCatMoveSync((CMovePBPtr) &pb);
  655.                 if ( error != noErr )
  656.                     goto error1;    /* back out gracefully by renaming both files to original names */
  657.                 
  658.                 /* move dest file to source directory */
  659.                 pb.copyParam.ioNamePtr = unique2Ptr;
  660.                 pb.copyParam.ioNewDirID = source->parID;
  661.                 pb.copyParam.ioDirID = dest->parID;
  662.                 error = PBCatMoveSync((CMovePBPtr) &pb);
  663.                 if ( error != noErr)
  664.                 {
  665.                     /* life is very bad.  We'll at least try to move source back */
  666.                     pb.copyParam.ioNamePtr = unique1Ptr;
  667.                     pb.copyParam.ioNewName = NULL;
  668.                     pb.copyParam.ioNewDirID = source->parID;
  669.                     pb.copyParam.ioDirID = dest->parID;
  670.                     (void) PBCatMoveSync((CMovePBPtr) &pb);    /* ignore errors */
  671.                     goto error1;    /* back out gracefully by renaming both files to original names */
  672.                 }
  673.             }
  674.             
  675.             /* Make unique1Ptr point to file in source->parID */
  676.             /* and unique2Ptr point to file in dest->parID */
  677.             /* This lets us fall through to the rename code below */
  678.             swapola = unique1Ptr;
  679.             unique1Ptr = unique2Ptr;
  680.             unique2Ptr = swapola;
  681.     
  682.             /* At this point, the files are in their new locations (if they were moved) */
  683.             /* Source is named Unique1 (name pointed to by unique2Ptr) and is in dest->parID */
  684.             /* Dest is named Unique2 (name pointed to by unique1Ptr) and is in source->parID */
  685.             /* Need to swap attributes except mod date and swap names */
  686.     
  687.             /* swap the catalog info by re-aiming the CInfoPB's */
  688.             catInfoSource.hFileInfo.ioNamePtr = unique1Ptr;
  689.             catInfoDest.hFileInfo.ioNamePtr = unique2Ptr;
  690.             
  691.             catInfoSource.hFileInfo.ioDirID = source->parID;
  692.             catInfoDest.hFileInfo.ioDirID = dest->parID;
  693.             
  694.             /* Swap the original mod dates with each file */
  695.             temp = catInfoSource.hFileInfo.ioFlMdDat;
  696.             catInfoSource.hFileInfo.ioFlMdDat = catInfoDest.hFileInfo.ioFlMdDat;
  697.             catInfoDest.hFileInfo.ioFlMdDat = temp;
  698.             
  699.             /* Here's the swap (ignore errors) */
  700.             (void) PBSetCatInfoSync(&catInfoSource); 
  701.             (void) PBSetCatInfoSync(&catInfoDest);
  702.             
  703.             /* rename unique2 back to dest */
  704. error1:
  705.             pb.ioParam.ioMisc = (Ptr) &(dest->name);
  706.             pb.ioParam.ioVersNum = 0;
  707.             pb.fileParam.ioNamePtr = unique2Ptr;
  708.             pb.fileParam.ioDirID = dest->parID;
  709.             (void) PBHRenameSync(&pb);    /* ignore errors */
  710.     
  711.             /* rename unique1 back to source */
  712. error2:
  713.             pb.ioParam.ioMisc = (Ptr) &(source->name);
  714.             pb.ioParam.ioVersNum = 0;
  715.             pb.fileParam.ioNamePtr = unique1Ptr;
  716.             pb.fileParam.ioDirID = source->parID;
  717.             (void) PBHRenameSync(&pb); /* ignore errors */
  718.         }
  719.         return ( error );
  720.     }
  721. }
  722.  
  723. /*****************************************************************************/
  724.  
  725. /* 
  726. **    Resource Manager FSp calls
  727. */
  728.  
  729. /*****************************************************************************/
  730.  
  731. pascal    short    FSpOpenResFileCompat(const FSSpec *spec,
  732.                                      SignedByte permission)
  733. {
  734.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  735.         return ( FSpOpenResFile(spec, permission) );
  736.     else
  737.         return ( HOpenResFile(spec->vRefNum, spec->parID, spec->name, permission) );
  738. }
  739.  
  740. /*****************************************************************************/
  741.  
  742. pascal    void    FSpCreateResFileCompat(const FSSpec *spec,
  743.                                        OSType creator,
  744.                                        OSType fileType,
  745.                                        ScriptCode scriptTag)
  746. {
  747.     OSErr            result;
  748.     CInfoPBRec        pb;
  749.     
  750.     if ( (FSHasFSSpecCalls() || QTHasFSSpecCalls()) && HasFSpCreateScriptSupportFix() )
  751.     {
  752.         FSpCreateResFile(spec, creator, fileType, scriptTag);
  753.         return;
  754.     }
  755.     else
  756.     {
  757.         HCreateResFile(spec->vRefNum, spec->parID, spec->name);
  758.         if ( ResError() == noErr )
  759.         {
  760.             /* get info on created item */
  761.             pb.hFileInfo.ioVRefNum = spec->vRefNum;
  762.             pb.hFileInfo.ioDirID = spec->parID;
  763.             pb.hFileInfo.ioNamePtr = (StringPtr) &(spec->name);
  764.             pb.hFileInfo.ioFDirIndex = 0;
  765.             result = PBGetCatInfoSync(&pb);
  766.             if ( result == noErr )
  767.             {
  768.                 /* Set fdScript in FXInfo */
  769.                 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  770.                 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  771.                 /* (smRoman is 0). fdScript is valid if high bit is set (see IM-6, page 9-38) */
  772.                 pb.hFileInfo.ioFlXFndrInfo.fdScript = (scriptTag >= smRoman) ?
  773.                                                         ((char)scriptTag | (char)0x80) :
  774.                                                         (smRoman);
  775.                 /* Set creator/fileType */
  776.                 pb.hFileInfo.ioFlFndrInfo.fdCreator = creator;
  777.                 pb.hFileInfo.ioFlFndrInfo.fdType = fileType;
  778.                 
  779.                 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  780.                 pb.hFileInfo.ioDirID = spec->parID;
  781.                 result = PBSetCatInfoSync(&pb);
  782.             }
  783.             /* Set ResErr low memory global to result */
  784.             LMSetResErr(result);
  785.         }
  786.         return;
  787.     }
  788. }
  789.  
  790. /*****************************************************************************/
  791.